package com.clean.notification.fcm

import android.os.Build
import android.util.Log
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.SPUtils
import com.clean.notification.BuildConfig
import com.clean.notification.app.BaseApplication
import com.clean.notification.device.CommonHeaderInterceptorPhone
import com.clean.notification.device.CountryManagerPhone
import com.clean.notification.device.DeviceInfoPhone
import com.clean.notification.device.LTRepositoryPhone
import com.clean.notification.noti.NotifyShowUtils
import com.drake.net.Post
import com.drake.net.request.BodyRequest
import com.drake.net.request.MediaConst
import com.drake.net.utils.scope
import com.drake.net.utils.scopeNet
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import okhttp3.RequestBody.Companion.toRequestBody

class MyFirebaseMessagingService : FirebaseMessagingService() {

    /**
     * 接收到消息时调用。
     *
     * @param remoteMessage 对象，表示从Firebase云消息接收到的消息。
     */
    // [START receive_message]
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        // (START_EXCLUDE)
        //消息分为数据消息和通知消息两种。处理数据消息
        //在onmessagerreceive无论应用程序是在前台还是后台。数据消息是类型
        //通常用于GCM。通知消息只在onmessagerreceived中接收，当应用程序
        //在前台。当应用程序在后台时，会显示自动生成的通知。
        //当用户点击通知时，他们返回到应用程序。消息包含两个通知
        //和数据载荷被视为通知消息。Firebase控制台总是发送通知
        //消息。更多信息请参见:https://firebase.google.com/docs/cloud-messaging/concept-options
        // (END_EXCLUDE)

        // TODO(developer): 在这里处理FCM消息。
        // 在这里没有收到消息?看看为什么会这样 : https://goo.gl/39bRNJ
        Log.e(TAG, "From: ${remoteMessage.from}")

        // 检查消息是否包含数据有效负载。
        if (remoteMessage.data.isNotEmpty()) {
            Log.e(TAG, "消息数据有效载荷  : ${remoteMessage.data}")
            val map: Map<String, String> = remoteMessage.data
            if (/* 检查数据是否需要长时间运行的作业进行处理 */ true) {
                // 对于长时间运行的任务(10秒或更长时间)，使用WorkManager。
                scheduleJob()
            } else {
                // 10秒内处理消息
                handleNow()
            }
        }

        // 检查消息是否包含通知有效负载。
        Log.e(TAG, "消息通知正文 : ${remoteMessage.notification?.body}")
        sendNotification()

        // 此外，如果您打算根据收到的FCM生成自己的通知
        // 信息，这是应该开始的地方。请参阅下面的sendNotification方法。
    }

    // [结束receive_message]
    // [START on_new_token]
    /**
     * 当FCM注册令牌更新时调用。如果前一个令牌的安全性被破坏，就可能发生这种情况。请注意，当最初生成FCM注册令牌时将调用该函数，因此这是您将检索令牌的地方。
     */
    override fun onNewToken(token: String) {
        Log.e(TAG, "Refreshed token  令牌更新 : $token")
        SPUtils.getInstance().put("token", token)
        SPUtils.getInstance().put("tokenTime", System.currentTimeMillis())
        // 如果要将消息发送到此应用程序实例或
        // 在服务器端管理此应用程序订阅，发送
        // FCM注册令牌到你的应用服务器。
        sendRegistrationToServer(token)
    }
    // [END on_new_token]

    /**
     * 使用WorkManager安排异步工作。
     */
    private fun scheduleJob() {
        // [START dispatch_job]
        val work = OneTimeWorkRequest.Builder(MyWorker::class.java).build()
        WorkManager.getInstance(this).beginWith(work).enqueue()
        // [END dispatch_job]
    }

    /**
     * 处理分配给broadcastreceiver的时间。
     */
    private fun handleNow() {
        Log.e(TAG, "短期任务完成.")
    }

    /**
     * 将令牌持久化到第三方服务器。
     *
     * 修改此方法，将用户的FCM注册令牌与任何服务器端帐户关联起来
     * 由您的应用程序维护。
     *
     * @param token 新令牌
     */
    var job: Job? = null
    private fun sendRegistrationToServer(token: String?) {
        // TODO: 实现这个方法来发送令牌到你的应用服务器。
        Log.e(TAG, "sendRegistrationTokenToServer 上报 ($token)")
        token?.let {
            job = GlobalScope.launch {
                scopeNet {
                    val result = Post<String>(BaseApplication.fcmPort) {
                        gson(genReportTokenBean(token))
                    }.await()
                    Log.e(
                        TAG, "sendRegistrationToServer:  上传token 结果 ${GsonUtils.toJson(result)}"
                    )
                }
            }
        }
    }

    fun BodyRequest.gson(tokenBean: ReportTokenBean) {
        this.body = GsonUtils.toJson(tokenBean).toRequestBody(MediaConst.JSON)
    }

    private fun genReportTokenBean(token: String): ReportTokenBean {
        val result = ReportTokenBean()
        result.token = token
        result.deviceId = DeviceInfoPhone.getInstance().getDeviceId();
        if (result.deviceId == null) {
            result.deviceId = ""
        }
        result.platform = "android"
        result.appVersion = LTRepositoryPhone.getVersion()
        result.channel = "unknown"
        result.apiLevel = Build.VERSION.RELEASE.toString()
        result.sdkInt = Build.VERSION.SDK_INT.toString()
        result.debug = BuildConfig.DEBUG.toString()
        result.packageName = LTRepositoryPhone.getPackageName()
        result.netType = "unknown"
        result.model = CommonHeaderInterceptorPhone.toURLEncoded(Build.MODEL)
        result.brand = CommonHeaderInterceptorPhone.toURLEncoded(Build.BRAND)
        result.country = CountryManagerPhone.getInstance().getCountry()
        result.mcc = 1
        result.isVpn = false

        result.appName = LTRepositoryPhone.getAppName()

        return result
    }


    /**
     * 创建并显示包含接收到的FCM消息的简单通知。
     *
     * @param messageBody 收到FCM消息体。
     */
    private fun sendNotification() {
        Log.e(TAG, "sendNotification:  发送通知 ~")
        NotifyShowUtils.tryShowLocalPush()
    }

    override fun onDestroy() {
        super.onDestroy()
        job?.let {
            it.cancel()
        }
    }

    companion object {

        private const val TAG = "aaaMyFirebaseMsgService"
    }

}
